﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using Cwing.UI.Controls;

namespace Cwing.UI.Validation.Manager
{
    /// <summary>
    /// Page Validation Manager
    /// Show be instance in onInitial Method
    /// </summary>
    public class PageValidationManager
    {
        private static readonly Object PageValidatingCommand = new object();

        private static readonly Object PageValidateCommand = new object();

        private EventHandlerList Events = new EventHandlerList();

        public PageValidationManager(Page instance)
        {
            Page = instance;

            ValidationControls = new List<IValidation>();
            Page.PreLoad += new EventHandler(Page_PreLoad);
            Page.PreRender += new EventHandler(Page_PreRender);
            Page.PreRenderComplete += new EventHandler(Page_PreRenderComplete);
        }

        void Page_PreLoad(object sender, EventArgs e)
        {
            _Initial();
        }

        void Page_PreRenderComplete(object sender, EventArgs e)
        {
            ScriptManager.Instance.RendInital(Page);
        }

        void Page_PreRender(object sender, EventArgs e)
        {

            ScriptManager.Instance.Rend(Page, ValidationControls);

            RenderValidationResult();
        }

        public Page Page
        {
            get;
            private set;
        }

        private void _Initial()
        {
            for (int i = 0; i < Page.Controls.Count; i++)
            {
                IValidation v = Page.Controls[i] as IValidation;
                if (v != null)
                {
                    if (v.Index == 0)
                    {
                        v.Index = ValidationControls.Count + 1;
                    }

                    if (v.ValidationType != ValidationType.Server && v.ErrorMessageContainer != null)
                    {
                        v.ErrorMessageContainer.Visible = true;
                        v.ErrorMessageContainer.UseForClient = true;
                    }
                    ValidationControls.Add(v);
                }
                if (Page.Controls[i].Controls.Count > 0)
                {
                    InitialValidationControl(Page.Controls[i].Controls);
                }
            }

            ValidationControls.Sort(delegate(IValidation v1, IValidation v2)
            {
                return v1.Index.CompareTo(v2.Index);
            });
        }

        private void InitialValidationControl(ControlCollection controls)
        {
            if (controls != null && controls.Count > 0)
            {
                for (int i = 0; i < controls.Count; i++)
                {
                    IValidation v = controls[i] as IValidation;
                    if (v != null)
                    {
                        if (v.Index == 0)
                        {
                            v.Index = ValidationControls.Count + 1;
                        }

                        if (v.ValidationType != ValidationType.Server && v.ErrorMessageContainer != null)
                        {
                            v.ErrorMessageContainer.Visible = true;
                            v.ErrorMessageContainer.UseForClient = true;
                        }

                        ValidationControls.Add(v);
                    }
                    if (controls[i].Controls.Count > 0)
                    {
                        InitialValidationControl(controls[i].Controls);
                    }
                }
            }
        }

        /// <summary>
        /// Rend error
        /// </summary>
        private void RenderValidationResult()
        {
            for (int i = 0; i < ValidationControls.Count; i++)
            {
                if (!ValidationControls[i].ValidationResult.IsEmpty && !ValidationControls[i].ValidationResult.Result)
                {
                    if (ValidationControls[i].ErrorMessageContainer != null && ValidationControls[i].IsRendError == false)
                    {
                        ValidationControls[i].IsRendError = true;
                        ValidationControls[i].ErrorMessageContainer.ErrorMessages.Add(ValidationControls[i].ValidationResult.Message);
                        ValidationControls[i].ErrorMessageContainer.Visible = true;
                    }
                }
            }

            for (int i = 0; i < CustomizeValidations.Count; i++)
            {
                if (!CustomizeValidations[i].ValidationResult.IsEmpty && !CustomizeValidations[i].ValidationResult.Result)
                {
                    if (CustomizeValidations[i].ErrorMessageContainer != null && CustomizeValidations[i].IsRendError == false)
                    {
                        CustomizeValidations[i].IsRendError = true;
                        CustomizeValidations[i].ErrorMessageContainer.ErrorMessages.Add(CustomizeValidations[i].ValidationResult.Message);
                        CustomizeValidations[i].ErrorMessageContainer.Visible = true;
                    }
                }
            }
        }

        public List<IValidation> ValidationControls
        {
            get;
            private set;
        }

        /// <summary>
        /// trigger before first control validate begin
        /// </summary>
        public event PageValidating PageValidating
        {
            add
            {
                Events.AddHandler(PageValidatingCommand, value);
            }
            remove
            {
                Events.RemoveHandler(PageValidatingCommand, value);
            }
        }

        private void OnPageValidating(PageValidatingEventArgs args, ValidationResult result)
        {
            PageValidating handler = Events[PageValidatingCommand] as PageValidating;
            if (handler != null)
            {
                handler(args, result);
            }
        }

        /// <summary>
        /// trigger after all control validate finished
        /// </summary>
        public event PageValidated PageValidated
        {
            add
            {
                Events.AddHandler(PageValidateCommand, value);
            }
            remove
            {
                Events.RemoveHandler(PageValidateCommand, value);
            }
        }

        private void OnPageValidated(PageValidatedEventArgs args, ValidationResult result)
        {
            PageValidated handler = Events[PageValidateCommand] as PageValidated;
            if (handler != null)
            {
                handler(args, result);
            }
        }

        /// <summary>
        /// execute control validate
        /// </summary>
        /// <returns></returns>
        public Boolean PageValidate()
        {
            return PageValidate(String.Empty);
        }

        public Boolean PageValidate(String groupName)
        {
            PageValidatingEventArgs preValidateArgs = new PageValidatingEventArgs();
            preValidateArgs.PageInstance = Page;
            preValidateArgs.Control = firstValidationControl;
            ValidationResult preResult = ValidationResult.Empty;
            OnPageValidating(preValidateArgs, preResult);

            if (preValidateArgs.Cancel == true)
            {
                if (preResult.IsEmpty)
                {
                    return true;
                }
                else
                {
                    CustomizeValidation preCV = new CustomizeValidation(String.Empty, null);
                    preCV.ValidationResult = new ValidationResult();
                    preCV.ValidationResult.Result = preResult.Result;
                    preCV.ValidationResult.Message = preResult.Message;
                    CustomizeValidations.Add(preCV);

                    //deal with Error message if have
                    return preCV.ValidationResult.Result;
                }
            }

            Boolean result = preResult.Result;

            //Start control validateion            
            for (int i = 0; i < ValidationControls.Count; i++)
            {
                //Group Name
                if (!String.IsNullOrEmpty(groupName) && ValidationControls[i].GroupName != groupName)
                    continue;

                ValidationResult _result = ValidationControls[i].Validate();
                if (!_result.IsEmpty)
                {
                    result = result & _result.Result;
                }
            }

            //Customize Validation
            for (int i = 0; i < CustomizeValidations.Count; i++)
            {
                //Group Name
                if (!String.IsNullOrEmpty(groupName) && ValidationControls[i].GroupName != groupName)
                    continue;

                ValidationResult _result = CustomizeValidations[i].Validate();
                if (!_result.IsEmpty)
                {
                    result = result & _result.Result;
                }
            }

            CustomizeValidation cv = new CustomizeValidation(String.Empty, null);
            cv.ValidationResult = new ValidationResult();
            cv.ValidationResult.Result = result;

            //raise PageValidated event
            PageValidatedEventArgs afterArgs = new PageValidatedEventArgs();
            afterArgs.PageInstance = Page;
            OnPageValidated(afterArgs, cv.ValidationResult);
            cv.ErrorMessageContainer = afterArgs.MessageContainer;
            CustomizeValidations.Add(cv);

            return cv.ValidationResult.Result;
        }

        private IValidation firstValidationControl
        {
            get
            {
                return (ValidationControls.Count > 0 ? ValidationControls[0] : null);
            }
        }

        private List<CustomizeValidation> customizeValidations = new List<CustomizeValidation>();

        public List<CustomizeValidation> CustomizeValidations
        {
            get
            {
                return customizeValidations;
            }
        }
    }
}
